#include "Math.hpp"
#include "Ray.hpp"
#include "Material.hpp"
#include "Shape.hpp"
#include "Scene.hpp"
#include "Renderer.hpp"
#include "Camera.hpp"
#include "Integrator.hpp"
#include "Log.hpp"
#include "Params.hpp"
#include "FileManager.hpp"

void printHelper() {
	cout << "invalid command." << endl;
	cout << "usage:" << endl << "\tRayTracer.exe [scene description file (.xml)]" << endl;
	cout << "example:" << endl;
	cout << "\tRayTracer.exe ../scenes/scene01/scene01.xml" << endl;
	cout << "\tRayTracer.exe ../scenes/scene02/scene02.xml" << endl;
	cout << "\tRayTracer.exe ../scenes/mitsuba/mitsuba.xml" << endl;
	cout << "\tRayTracer.exe ../scenes/shader_ball/shader_ball.xml" << endl;
	cout << "\tRayTracer.exe ../scenes/killeroo/killeroo.xml" << endl;
	cout << endl;
}

int main(int argc, char* argv[])
{
	if (argc < 2) {
		printHelper();
		return 1;
	}
	log_system_init();

	auto currentPath = FileManager::currentPath();

#ifdef RENDERFISH_PLATFORM_IS_WINDOWS
	//string xml_path = "../scenes/scene01/scene01.xml";
	string xml_path = "../scenes/scene02/scene02.xml";
	//string xml_path = "../scenes/mitsuba/mitsuba.xml";
	//string xml_path = "../scenes/shader_ball/shader_ball.xml";
#else
	//string xml_path = "/Users/yushroom/program/graphics/RayTracer/scenes/scene01/scene01.xml";
	//string xml_path = "/Users/yushroom/program/graphics/RayTracer/scenes/mitsuba/mitsuba.xml";
	//string xml_path = "/Users/yushroom/program/graphics/RayTracer/scenes/scene02/scene02.xml";
    string xml_path = "/Users/yushroom/program/graphics/RayTracer/scenes/shader_ball/shader_ball.xml";
#endif

	if (argc >= 2)
		xml_path = argv[1];

	string canvas_path = "";
	if (argc >= 3) {
		canvas_path = argv[2];
	} else {
		size_t pos = xml_path.find_last_of(".");
		Assert(pos != string::npos);
		canvas_path = xml_path.substr(0, pos) + ".bmp";
	}

	FileManager::setWorkingDir(FileManager::parentPath(xml_path));
	
    RootParams root_params(xml_path);
    
    auto integrator	= SurfaceIntegrator::create(root_params.child("integrator"));
    auto canvas		= Canvas::create(root_params.child("canvas"));
    auto camera		= Camera::create(root_params.child("camera"), canvas.getAspect());
    auto scene		= Scene::create(root_params.child("scene"));
	auto renderer	= Renderer::create(root_params.child("renderer"));
    
	renderer->render(*scene, camera, canvas, integrator);
    
	canvas.write(canvas_path);

    return 0;
}